﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using EnvDTE;
using EnvDTE80;

namespace CodeJumper
{
    public class ApplicationConfiguration
    {
        private readonly Dictionary<string, BitmapImage> _imageSources = new Dictionary<string, BitmapImage>();


        public Brush AccessiblityInternal = Brushes.White;
        public Brush AccessiblityPrivate = Brushes.White;
        public Brush AccessiblityProtected = Brushes.White;
        public Brush AccessiblityProtectedInternal = Brushes.White;
        public Brush AccessiblityPublic = Brushes.White;
        public double AccessorMarginOffset = -16;
        public Label AddinFont;
        public int ApplicationId;
        public Brush ClassBackgroundBrush = Brushes.White;
        public Brush ClassTextBrush = Brushes.Black;
        public CodeModelEvents CodeModelEvents;
        public Brush DelegateTextBrush = Brushes.DarkGray;
        public Mutex DispatchingMutex = new Mutex(false);
        public Semaphore DispatcherSemaphore = new Semaphore(1, 1);
        public DocumentEvents DocumentEvents;
        public string DocumentFilename;

        public DocumentParser DocumentParser;
        public ProjectItem DocumentProjectItem;

        public HookInformation HookInformation;
        public Style EasyButtonStyle;
        public Brush EnumBackgroundBrush = Brushes.White;
        public Brush EnumTextBrush = Brushes.DarkGray;
        public Brush EventTextBrush = Brushes.DarkGray;
        public Style ExpanderStyle;
        public string ExtensionDirectory; // Location of DLL and Themes
        public double HyperlinkFontSize = 11;
        public Thickness HyperlinkPadding = new Thickness(0, 0, 0, 0);

        // Addin Visuals


        // Space between the pictures and the text

        public Thickness HyperlinkTextImageSpacer = new Thickness(3, 0, 0, 0);
        public Brush InterfaceBackgroundBrush = Brushes.White;
        public Brush MethodParametersTextBrush = Brushes.LightGray;
        public Brush MethodTextBrush = Brushes.DarkGray;
        public Brush MouseOverMemberBackgroundBrush = Brushes.Beige;
        public Brush NamespaceTextBrush = Brushes.Black;

        // Stackables

        public Brush NamspaceBackgroundBrush = Brushes.White;
        public Brush PropertyTextBrush = Brushes.DarkGray;
        public bool SortAlphabetically = true;
        public Border StackableBorder = new Border();
        public Brush StructBackgroundBrush = Brushes.White;
        public Brush StructTextBrush = Brushes.DarkGray;
        public string ThemeFilename = "Default.xaml";
        public Brush VariableTextBrush = Brushes.DarkGray;
        public Brush ViewPortBackgroundBrush = Brushes.Transparent;
        public Brush ViewPortSplitterBackgroundBrush = Brushes.LightGray;
        public ElementView elementView;
        public Image privateImage;
        private ThemeResource themeResource;

        public ApplicationConfiguration()
        {
            AddImage("class", "Icons/class.png");
            AddImage("staticclass", "Icons/staticclass.png");
            AddImage("constructor", "Icons/constructor.png");
            AddImage("enum", "Icons/enum.png");
            AddImage("enumvalue", "Icons/enumvalue.png");
            AddImage("delegate", "Icons/delegate.png");
            AddImage("namespace", "Icons/namespace.png");
            AddImage("field", "Icons/field.png");
            AddImage("fieldreadonly", "Icons/fieldreadonly.png");
            AddImage("operator", "Icons/operator.png");
            AddImage("property", "Icons/property.png");
            AddImage("indexer", "Icons/indexer.png");
            AddImage("constant", "Icons/literal.png");
            AddImage("interface", "Icons/interface.png");
            AddImage("extensionmethod", "Icons/extensionmethod.png");
            AddImage("method", "Icons/method.png");
            AddImage("virtualmethod", "Icons/virtualmethod.png");
            AddImage("structure", "Icons/struct.png");
            AddImage("event", "Icons/event.png");

            AddImage("private", "Icons/overlayprivate.png");
            AddImage("protected", "Icons/overlayprotected.png");
            AddImage("internal", "Icons/overlayinternal.png");
            AddImage("protectedinternal", "Icons/overlayprotectedinternal.png");
            AddImage("privateinternal", "Icons/privateinternal.png");

            AddImage("static", "Icons/overlaystatic.png");

            ExtensionDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        }

        public bool HideVariables { get; set; }
        public bool HideProperties { get; set; }

        public void LoadThemes()
        {
            if (themeResource == null)
                themeResource = new ThemeResource(this);
            bool result = themeResource.Load(ThemeFilename);
            if (result == false)
            {
                MessageBox.Show("Unable to load theme resource.");
                return;
            }

            AddinFont = themeResource.FindObject("AddinFont") as Label;

            MouseOverMemberBackgroundBrush = themeResource.FindBrush("MouseOverMemberBackgroundBrush");
            ViewPortBackgroundBrush = themeResource.FindBrush("ViewPortBackgroundBrush");
            NamspaceBackgroundBrush = themeResource.FindBrush("NamespaceBackgroundBrush");
            ClassBackgroundBrush = themeResource.FindBrush("ClassBackgroundBrush");
            EnumBackgroundBrush = themeResource.FindBrush("EnumBackgroundBrush");
            InterfaceBackgroundBrush = themeResource.FindBrush("InterfaceBackgroundBrush");
            StructBackgroundBrush = themeResource.FindBrush("StructBackgroundBrush");

            MethodTextBrush = themeResource.FindBrush("MethodTextBrush");
            StackableBorder = themeResource.FindObject("StackableBorder") as Border;
            ViewPortSplitterBackgroundBrush = themeResource.FindBrush("ViewPortSplitterBackgroundBrush");

            NamespaceTextBrush = themeResource.FindBrush("NamespaceTextBrush");
            ClassTextBrush = themeResource.FindBrush("ClassTextBrush");
            EnumTextBrush = themeResource.FindBrush("EnumTextBrush");
            MethodTextBrush = themeResource.FindBrush("MethodTextBrush");
            MethodParametersTextBrush = themeResource.FindBrush("MethodParametersTextBrush");
            PropertyTextBrush = themeResource.FindBrush("PropertyTextBrush");
            VariableTextBrush = themeResource.FindBrush("VariableTextBrush");
            DelegateTextBrush = themeResource.FindBrush("DelegateTextBrush");
            EventTextBrush = themeResource.FindBrush("EventTextBrush");
            StructTextBrush = themeResource.FindBrush("StructTextBrush");

            AccessiblityPublic = themeResource.FindBrush("AccessiblityPublic");
            AccessiblityPrivate = themeResource.FindBrush("AccessiblityPrivate");
            AccessiblityProtected = themeResource.FindBrush("AccessiblityProtected");
            AccessiblityProtectedInternal = themeResource.FindBrush("AccessiblityProtectedInternal");
            AccessiblityInternal = themeResource.FindBrush("AccessiblityInternal");
        }

        public void CreateBinding(string path, DependencyProperty property, Control control)
        {
            var binding = new Binding();
            binding.Source = this;
            binding.Path = new PropertyPath(path);
            control.SetBinding(property, binding);
        }

        private BitmapImage LoadBitmapImage(string relativeResourcePath)
        {
            var img = new BitmapImage();
            img.BeginInit();
            img.UriSource = new Uri(string.Format("pack://application:,,,/{0}", relativeResourcePath));
            img.EndInit();
            return img;
        }

        private void AddImage(string name, string resource)
        {
            BitmapImage img = LoadBitmapImage(resource);
            _imageSources.Add(name, img);
        }

        public BitmapImage GetImage(string name)
        {
            if (_imageSources.ContainsKey(name) == false)
                return null;

            return _imageSources[name];
        }


        public void InvokeCompleteUpdate()
        {
            if (DispatcherSemaphore.WaitOne(1) == false)
            {
                Trace.WriteLine("Dispatcher already queued.");
                return;
            }

            //elementView.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action) (() => { elementView.InitiateUpdate(); }));
            elementView.InitiateUpdate();
        }

        public void InvokeDeletionUpdate(CodeElement element)
        {
            if (DispatcherSemaphore.WaitOne(1) == false)
            {
                Trace.WriteLine("Dispatcher already queued.");
                return;
            }

            elementView.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action) (() => { elementView.DeleteElement(element); }));
            //elementView.DeleteElement(element);
        }

        public void InvokeChangeUpdate(CodeElement element)
        {
            if (DispatcherSemaphore.WaitOne(1) == false)
            {
                Trace.WriteLine("Dispatcher already queued.");
                return;
            }

            elementView.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)(() => { elementView.ChangeElement(element); }));
            //elementView.ChangeElement(element);
        }
        
    }
}